﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;

namespace BSCMFF.Core.BusinessLayer
{
    /// <summary>
    /// Help class for parsing csv file.
    /// </summary>
    /// <remarks></remarks>
    public class CSVReader
    {
        private Stream objStream;

        private StreamReader objReader;
        

        //add name space System.IO.Stream

        /// <summary>
        /// Initializes a new instance of the <see cref="CSVReader"/> class.
        /// </summary>
        /// <param name="filestream">The filestream.</param>
        /// <remarks></remarks>
        public CSVReader(Stream filestream) : this(filestream, null) { }

        
        /// <summary>
        /// Initializes a new instance of the <see cref="CSVReader"/> class.
        /// </summary>
        /// <param name="filestream">The filestream.</param>
        /// <param name="enc">The enc.</param>
        /// <remarks></remarks>
        public CSVReader(Stream filestream, Encoding enc)
        {

            this.objStream = filestream;

            //check the Pass Stream whether it is readable or not

            if (!filestream.CanRead)
            {
                return;
            }

            objReader = (enc != null) ? new StreamReader(filestream, enc) : new StreamReader(filestream);
        }

        

        /// <summary>
        /// Parse the Line
        /// </summary>
        /// <returns>Line in csv in form of array of chars</returns>
        /// <remarks></remarks>
        public string[] GetCSVLine()
        {

            string data = objReader.ReadLine();

            if (data == null) return null;

            if (data.Length == 0) return new string[0];

            ArrayList result = new ArrayList();

            //parsing CSV Data

            ParseCSVData(result, data);

            return (string[])result.ToArray(typeof(string));

        }

        /// <summary>
        /// Parses the CSV data.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <param name="data">The data.</param>
        /// <remarks></remarks>
        private void ParseCSVData(ArrayList result, string data)
        {
            int position = -1;

            while (position < data.Length)

                result.Add(ParseCSVField(ref data, ref position));
        }
        
        /// <summary>
        /// Parses the CSV field.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="StartSeperatorPos">The start seperator pos.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private string ParseCSVField(ref string data, ref int StartSeperatorPos)
        {
            if (StartSeperatorPos == data.Length - 1)
            {
                StartSeperatorPos++;
                return "";
            }

            int fromPos = StartSeperatorPos + 1;

            if (data[fromPos] == '"')
            {
                int nextSingleQuote = GetSingleQuote(data, fromPos + 1);

                int lines = 1;

                while (nextSingleQuote == -1)
                {

                    data = data + "\n" + objReader.ReadLine();

                    nextSingleQuote = GetSingleQuote(data, fromPos + 1);

                    lines++;

                    if (lines > 20)

                        throw new Exception("lines overflow: " + data);
                }

                StartSeperatorPos = nextSingleQuote + 1;

                string tempString = data.Substring(fromPos + 1, nextSingleQuote - fromPos - 1);

                tempString = tempString.Replace("'", "''");

                return tempString.Replace("\"\"", "\"");

            }

            int nextComma = data.IndexOf(',', fromPos);

            if (nextComma == -1)
            {

                StartSeperatorPos = data.Length;

                return data.Substring(fromPos);

            }
            else
            {

                StartSeperatorPos = nextComma;

                return data.Substring(fromPos, nextComma - fromPos);

            }
        }
        
        /// <summary>
        /// Gets the single quote.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="SFrom">The position from.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private int GetSingleQuote(string data, int SFrom)
        {
            int i = SFrom - 1;

            while (++i < data.Length)

                if (data[i] == '"')
                {
                    if (i < data.Length - 1 && data[i + 1] == '"')
                    {
                        i++;
                        continue;
                    }
                    else
                        return i;
                }
            return -1;
        }

    }
}
